#include <kutils.h>
#include "syscall.h"
#include "display.h"
#include "irq.h"
#include "memory.h"

void syscall_handler(struct regs *r);

void (*syscall_handlers[SYSCALL_MAX])(syscall_regs_t *r);

s32int install_syscall(u32int syscall_number, void (*handler)(syscall_regs_t *r))
{
	//syscall too high
	if(syscall_number > SYSCALL_MAX)
		return 0;

	//null handler
	if(!handler)
		return 0;

	//this syscall is being handled by something else already
	if(syscall_handlers[syscall_number])
		return 0;

	syscall_handlers[syscall_number] = handler;
	return 1;
}

//Important note: r is just a pos32inter to the stack
void syscall_handler(struct regs *r)
{
	//blank function pos32inter
	void (*handler)(syscall_regs_t *r);
	syscall_regs_t *sys_regs = (syscall_regs_t*)kmalloc(sizeof(syscall_regs_t));

	if(r->edx > SYSCALL_MAX)
	{
		kfree(sys_regs);
		r->edx = 0;
		return;
	}

	if(!syscall_handlers[r->edx])
	{
		kfree(sys_regs);
		r->edx = 0;
		return;
	}

	//copy the register values off of the stack and s32into the sys_regs structure
	sys_regs->arg1 = r->eax; sys_regs->arg2 = r->ebx; sys_regs->arg3 = r->ecx; 
	sys_regs->call = r->edx; sys_regs->arg4 = r->esi; sys_regs->arg5 = r->edi;

	handler = syscall_handlers[(u8int)r->edx];
	enable_interrupts();
	handler(sys_regs);
	disable_interrupts();

	//copy the register values out of the sys_regs structure back s32into the stack
	r->eax = sys_regs->res1; r->ebx = sys_regs->res2; r->ecx = sys_regs->res3; 
	r->edx = sys_regs->success; r->esi = sys_regs->res4; r->edi = sys_regs->res5;

	kfree(sys_regs);
	return;
}

void init_syscall(void)
{
#ifdef FLUIDIUM_DEBUG
	write_string("Syscall: Init\n");
#endif
	irq_install_handler(64, syscall_handler);
}
